//
//  WCWebLoader.m
//  WebExtractSimpleViewer
//
//  Created by Daniel Braun on 10/03/07.
//  Copyright 2007 Daniel Braun http://page-appart.net, http://braun.daniel.free.fr All rights reserved.
//

#import "WCWebLoader.h"
#import "WCconfig.h"
#import "WCUrlAccess.h"

#ifndef NODOM
#import <WebKit/WebKit.h>
#import <WebKit/WebView.h>
#import <WebKit/DOM.h>
#import <WebKit/DOMExtensions.h>
#import <WebKit/DOMHtml.h>
#else 
#import "WCDom.h"
#endif

@implementation WCWebLoader
- (id) init {
	self = [super init];
	if (self != nil) {
		receivedData=[[NSMutableData dataWithCapacity:(1024*64)] retain];
	}
	return self;
}

- (void) cleanEndCnx
{
	[cnx cancel];
	[cnx release]; cnx=nil;
	[loadCallBackTarget release]; loadCallBackTarget=nil; 
	loadCallBackAction=(SEL)0;
	[loadCallBackPrivate release]; loadCallBackPrivate=nil;
}

- (void) dealloc {
	[self  cleanEndCnx];
	[urlAccess release];
	[bodyVariables release];
	[receivedData release];
	[qdelegate release];
	[super dealloc];
}

- (void) resetContext
{
}

- (BOOL) loadPageAndPerform:(SEL)sel target:(id)obj private:(id)p
{
	//NSLog(@"loading %@\n", url);
	// build request
	[self cleanEndCnx];
	loadCallBackAction=sel;
	loadCallBackTarget=[obj retain];
	loadCallBackPrivate=[p retain];
	
	NSMutableURLRequest *req=[[[NSMutableURLRequest alloc] init]autorelease];
	[req setCachePolicy:NSURLRequestReloadIgnoringCacheData];
	[req setTimeoutInterval:60.0];
	[req setHTTPMethod:@"GET" ];
	[req setURL:url];	
	if (urlAccess) req=[urlAccess updateRequest:req withBodyVariables:bodyVariables]; //XXX
	/*
	 * pretend we are WebKit/Safari. This is not true at all (we are NSConnection), but some
	 * sites will change output depending on browser. And DOM tree would be different from
	 * the tree retrieved by WebExtractor
	 */
	
	//[req setValue:@"Mozilla/5.0 (Macintosh; U; Intel Mac OS X; fr) AppleWebKit/419 (KHTML, like Gecko)" forHTTPHeaderField:@"User-Agent"];
	[req setValue:@"Mozilla/5.0 (Macintosh; U; Intel Mac OS X; fr-fr) AppleWebKit/523.15.1 (KHTML, like Gecko)"  forHTTPHeaderField:@"User-Agent"];
	if (0) {
		[req setValue: @"...."/*[ref absoluteString]*/
	   forHTTPHeaderField:@"Referer"];
	}
	[receivedData setLength:0];
	cnx=[[NSURLConnection alloc] initWithRequest:req delegate:self];
	return YES;
}

- (void) setUrl:(NSURL *)u delegateQuery:(id)dq urlAccess:(WCUrlAccess *)ua bodyVariables:(NSDictionary *)d;
{
	NSAssert(ua, @"url access not set\n"); // assert to be removed
	[url release];
	[urlAccess release];
	[bodyVariables release];
	bodyVariables=[d retain];
	urlAccess=[ua retain];
	if ([u isKindOfClass:[NSString class]]) url=[NSURL URLWithString:(NSString *)u];
	else url=[u retain];
	[qdelegate release];
	qdelegate=[dq retain];
}

- (NSData *) dhtml 
{
	return receivedData;
}
- (NSString *) html
{
	if (![receivedData length]) return nil;
	NSString *s=[[[NSString alloc]initWithData:receivedData
					  encoding:NSUTF8StringEncoding]autorelease];
	if (!s) s=[[[NSString alloc]initWithData:receivedData
					encoding:NSISOLatin1StringEncoding]autorelease];
	return s;
}
- (DOMHTMLElement *) rootDOM
{
	NSString *s=[self html];
	if (!s) return nil;
	
#ifndef NODOM
#error not supported
	// beurk
#if 0
	WebView *wv=[[WebView alloc]init];
	WebFrame *w=[wv mainFrame];
	[w loadHTMLString:s baseURL:nil];
	DOMDocument *d=[w DOMDocument];
	DOMElement *e=[d documentElement];
	[wv release];
#endif
	DOMHTMLElement *e=[[DOMHTMLElement alloc]init];
	[e setOuterHTML:s];
#endif
	NSError *err=nil;
	NSXMLDocument *doc=[[NSXMLDocument alloc]initWithXMLString:s 
							   options:0|NSXMLDocumentTidyHTML
							     error:&err];
	if (!doc) NSLog(@"error processing html: %@\n", err);
	DOMHTMLElement *root=[doc rootElement];
	[[root retain]autorelease];
	[doc release];
	return root;
}

- (void) loadFailure
{
	NSLog(@"load failure\n");
	// clean first for loadCallBackTarget may initiate new req
	id _t = [[loadCallBackTarget retain]autorelease];
	id _p = [[loadCallBackPrivate retain]autorelease];
	SEL _a=loadCallBackAction;
	//[self cleanEndCnx];
	
	[_t performSelector:_a 
		 withObject:self withObject:_p];
}

- (void) loadSuccess:(NSData *)data
{
	// clean first for loadCallBackTarget may initiate new req
	id _t = [[loadCallBackTarget retain]autorelease];
	id _p = [[loadCallBackPrivate retain]autorelease];
	SEL _a=loadCallBackAction;
	//[self cleanEndCnx];
	
	[_t performSelector:_a 
		 withObject:self withObject:_p];
}

- (BOOL) loadHtml:(NSString *)html andPerform:(SEL)sel target:(id)obj private:(id)p
{
	NSLog(@"load html %@\n", html);
	[self cleanEndCnx];
	loadCallBackAction=sel;
	loadCallBackTarget=[obj retain];
	loadCallBackPrivate=[p retain];
	[receivedData release];
	receivedData=[[html dataUsingEncoding:NSUTF8StringEncoding]retain];
	[self loadSuccess:receivedData];
	return YES;
}

/// cnx delegate

-(NSURLRequest *)connection:(NSURLConnection *)connection
            willSendRequest:(NSURLRequest *)request
           redirectResponse:(NSURLResponse *)redirectResponse
{   
	NSURLRequest *newRequest=request;
	NSLog(@"redirect to %@ (%@)\n", [[redirectResponse URL] absoluteString], [redirectResponse URL]);
	if (0 && redirectResponse) {
		newRequest=nil;
	}
	return newRequest;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
	//NSLog(@"response for  url %@\n", [_url absoluteString]);
	[receivedData setLength:0];
	//[self setMimeType:[response MIMEType]];
	if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
		NSHTTPURLResponse *r=(NSHTTPURLResponse *)response;
		int code=[r statusCode];
		NSDictionary *d=[r allHeaderFields];
		if (code != 200) {

			NSLog(@"got response %d h:%@\n", code, d);
		}
	}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
	//printf("data for  url %s, %d bytes\n", [[_url absoluteString] UTF8String], [data length]);
	// append the new data to the receivedData
	[receivedData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
	// release the connection, and the data object
	NSLog(@"error for  url %@ (%@)\n", [url absoluteString], error);
	NSAssert(connection == cnx, @"not current cnx");
	[cnx release];
	cnx=nil;
	[receivedData setLength:0];
	
	// inform the user
	NSLog(@"Connection failed! Error - %d %@ %@ %@\nfailure reason: %@\nrecovery: %@\n",
	      [error code], [error domain],
	      [error localizedDescription],
	      [[error userInfo] objectForKey:NSErrorFailingURLStringKey],
	      [error localizedFailureReason], [error localizedRecoverySuggestion]);
	[self performSelector:@selector( loadFailure )
		   withObject:receivedData
		   afterDelay:0.0];
}

- (NSString *) authName
{
	return  @"anonymous";
}
- (NSString *) authPassword
{
	return  @"nobody@nowhere";
}

-(void)connection:(NSURLConnection *)connection
        didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
	NSLog(@"auth for  url %@\n", [url absoluteString]);
	if ([challenge previousFailureCount] == 0) {
		NSURLCredential *newCredential;
		newCredential=[NSURLCredential credentialWithUser:[self authName]
							 password:[self authPassword]
						      persistence:NSURLCredentialPersistenceNone];
		[[challenge sender] useCredential:newCredential
		       forAuthenticationChallenge:challenge];
	} else {
		[[challenge sender] cancelAuthenticationChallenge:challenge];
		// inform the user that the user name and password
		// in the preferences are incorrect
		//[self showPreferencesCredentialsAreIncorrectPanel:self];
	}
}

-(NSCachedURLResponse *)connection:(NSURLConnection *)connection
                 willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
	return nil;
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
	if (0!=[receivedData length]) {
		[cnx release]; cnx=nil;
		[self performSelector:@selector( loadSuccess: )
		   withObject:receivedData
		   afterDelay:0.0];
	} else {
		[self cleanEndCnx];
		[self performSelector:@selector( loadFailure )
			   withObject:receivedData
			   afterDelay:0.0];
	}
}

@end
